package org.example.utils;

import org.example.entity.EdgeBean;
import org.example.entity.GraphBean;
import org.example.entity.NodeBean;
import org.javatuples.Triplet;

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

public class GraphUtil {
    static public GraphBean getGraph(ArrayList<Triplet<String, String, String>> triplets) {
        GraphBean graphBean = new GraphBean();

        for (Triplet<String, String, String> triplet : triplets) {

            // update from node
            String fromLabel = triplet.getValue0();
            AtomicInteger fromId = new AtomicInteger();
            findNodeByLabel(graphBean, fromLabel, (id) -> {
                if (id == -1) {
                    NodeBean from =  new NodeBean(id, fromLabel, false);
                    fromId.set(graphBean.addNode(from).lastIndexOf(from));
                }
            });

            // update to node
            String toLabel = triplet.getValue1();
            AtomicInteger toId = new AtomicInteger();
            findNodeByLabel(graphBean, toLabel, (id) -> {
                if (id == -1) {
                    NodeBean to = new NodeBean(id, toLabel, false);
                    toId.set(graphBean.addNode(to).indexOf(to));
                }
            });

            // create edge
            String value = triplet.getValue2();
            EdgeBean edge = new EdgeBean(fromId.get(), toId.get(), value);
            edge.setEdgeId(graphBean.addEdge(edge).lastIndexOf(edge));

            // create next
            graphBean.addNextById(edge.getFromId(), edge.getEdgeId());
        }

        return graphBean;
    }


    static public int findNodeByLabel(GraphBean graphBean, String label, Consumer<Integer> consumer) {
        int id = -1;
        for (NodeBean node : graphBean.getNodes()) {
            if (node.getLabel().equals(label)) {
                id = node.getId();
            }
        }
        if (consumer != null) {
            consumer.accept(id);
        }
        return id;
    }

    static public void printGraph(GraphBean graphBean) {
        for (int i = 0, L = graphBean.getNext().size(); i < L; i ++ ) {
            ArrayList<Integer> edges = graphBean.getNext().get(i);

            System.out.printf("[%s]", graphBean.getNodes().get(i));

            for (int edgeId : edges) {
                if (edges.indexOf(edgeId) != 0) {
                    System.out.print(" -> ");
                } else {
                    System.out.print(" ");
                }

                EdgeBean edge = graphBean.getEdges().get(edgeId);
                System.out.printf("(%s, %s)\n",
                        edge.getValue(),
                        graphBean.getNodes().get(edge.getToId()).getLabel());
            }
        }
    }
}
